using System;
using System.Collections.Generic;
using Castle.Core;
using Castle.Core.Configuration;
using Castle.Core.Interceptor;
using Castle.MicroKernel.Facilities;

namespace Castle.Facilities.PolicyInjection
{
    public class PolicyFacility : AbstractFacility
    {
        private static IDictionary<Type, object> _handlerInstanceCollection;

        internal static IDictionary<Type, object> HandlerInstanceCollection
        {
            get
            {
                return _handlerInstanceCollection;
            }
        }

        private static IDictionary<Type, ComponentPolicy> _policyCollection;        

        public static T GetHandler<T>() where T : class
        {
            Type type = typeof(T);
            foreach (KeyValuePair<Type, object> kvp in _handlerInstanceCollection)
            {
                if (type.IsInstanceOfType(kvp.Value) == true)
                {
                    return kvp.Value as T;
                }
            }            
            throw new NullReferenceException("No handler of type " + typeof(T).FullName);
        }

        protected override void Init()
        {
            _handlerInstanceCollection = new Dictionary<Type, object>();
            _policyCollection = new Dictionary<Type, ComponentPolicy>();
            Kernel.AddComponent("Policy.Interceptor", typeof(PolicyInterceptor), LifestyleType.Transient);
            Kernel.ComponentRegistered += new Castle.MicroKernel.ComponentDataDelegate(ComponentRegistered);
        }        

        private void ComponentRegistered(string key, Castle.MicroKernel.IHandler component)
        {
            IConfiguration policyConfiguration = component.ComponentModel.Configuration.Children["policy"];
            if (policyConfiguration != null)
            {
                ComponentPolicy policy = new ComponentPolicy(policyConfiguration, this, key, component.ComponentModel);
                _policyCollection.Add(component.ComponentModel.Service, policy);
                InterceptorReference interceptorReference = new InterceptorReference(typeof(PolicyInterceptor));                
                component.ComponentModel.Interceptors.Add(interceptorReference);
                component.ComponentModel.ExtendedProperties[Literals.policy] = policy;                
            }            
        }        
    }
}
